home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Technology Seed / ADC Seed CD - July 1999.toast / USB / Mac OS USB DDK v1.2 / Examples / PrinterClassDriver / TradDriverLoaderLib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-15  |  21.7 KB  |  770 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        TradDriverLoaderLib.c
  3.  
  4.     Contains:    Implementation for the pseudo-DriverLoaderLib for 'DRVR's.
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.  
  9.  
  10.     Copyright:    © 1996-1998 by Apple Computer, Inc., all rights reserved.
  11.  
  12. */
  13.  
  14. #include <LowMem.h>
  15. #include <DriverGestalt.h>
  16. #include <TextUtils.h>
  17.  
  18. // Switched from using:
  19. //
  20. //   #include <PLStringFuncs.h>
  21. //
  22. // to using BlockMoveData because it's so hard to get PLstrcpy working
  23. // across a zillion different compilers.  *sigh*
  24.  
  25. #include "TradDriverLoaderLib.h"
  26.  
  27. ///////////////////////////////////////////////////////////////////////////
  28.  
  29. extern pascal SInt16 TradHigherDriverVersion(NumVersion *dv1, NumVersion *dv2)
  30. {
  31.     UInt16 nonRelRev1, nonRelRev2;
  32.  
  33.     if (dv1->majorRev           > dv2->majorRev)        return  1;
  34.     if (dv1->majorRev           < dv2->majorRev)        return -1;
  35.     if (dv1->minorAndBugRev     > dv2->minorAndBugRev)  return  1;
  36.     if (dv1->minorAndBugRev     < dv2->minorAndBugRev)  return -1;
  37.     if (dv1->stage              > dv2->stage)           return  1;
  38.     if (dv1->stage              < dv2->stage)           return -1;
  39.  
  40.     nonRelRev1 = dv1->nonRelRev;
  41.     nonRelRev2 = dv2->nonRelRev;
  42.     
  43.     if (dv1->stage == finalStage) {
  44.         if (dv1->nonRelRev == 0)                 nonRelRev1 = 0xFFFF;
  45.         if (dv2->nonRelRev == 0)                 nonRelRev2 = 0xFFFF;
  46.     }
  47.  
  48.     if (nonRelRev1 > nonRelRev2)                        return  1;
  49.     if (nonRelRev1 < nonRelRev2)                        return -1;
  50.  
  51.     return 0;
  52. }
  53.  
  54.  
  55. ///////////////////////////////////////////////////////////////////////////
  56.  
  57. extern pascal UnitNumber TradHighestUnitNumber(void)
  58.     // See comment in header file.
  59. {
  60.     return ( LMGetUnitTableEntryCount() - 1);
  61. }
  62.  
  63. ///////////////////////////////////////////////////////////////////////////
  64.  
  65. extern pascal Boolean TradDriverGestaltIsOn(DriverFlags flags)
  66.     // See comment in header file.
  67. {
  68.     return ( (flags & kmDriverGestaltEnableMask) != 0 );
  69. }
  70.  
  71. ///////////////////////////////////////////////////////////////////////////
  72.  
  73. static OSErr DriverGestaltOnOff(DriverRefNum refNum, Boolean setIt)
  74.     // This routine is called by TradDriverGestaltOn and
  75.     //  TradDriverGestaltOff to either set or clear the
  76.     //  kmDriverGestaltEnableMask bit in the DCE flags.
  77. {
  78.     OSErr err;
  79.     AuxDCEHandle thisDCE;
  80.     
  81.     // First called TradGetDriverInformation to validate the refNum
  82.     //  and verify that the driver exists.
  83.     err = TradGetDriverInformation(refNum, nil, nil, nil, nil);
  84.     if (err == noErr) {
  85.         thisDCE = (AuxDCEHandle) GetDCtlEntry(refNum);
  86.         if (setIt) {
  87.             (**thisDCE).dCtlFlags |= kmDriverGestaltEnableMask;
  88.         } else {
  89.             (**thisDCE).dCtlFlags &= ~kmDriverGestaltEnableMask;
  90.         }
  91.     }
  92.     
  93.     return (err);
  94. }
  95.  
  96. ///////////////////////////////////////////////////////////////////////////
  97.  
  98. extern pascal OSErr TradDriverGestaltOn(DriverRefNum refNum)
  99.     // See comment in header file.
  100. {
  101.     return ( DriverGestaltOnOff(refNum, true) );
  102. }
  103.  
  104. ///////////////////////////////////////////////////////////////////////////
  105.  
  106. extern pascal OSErr TradDriverGestaltOff(DriverRefNum refNum)
  107.     // See comment in header file.
  108. {
  109.     return ( DriverGestaltOnOff(refNum, false) );
  110. }
  111.  
  112. ///////////////////////////////////////////////////////////////////////////
  113.  
  114. extern pascal OSErr TradOpenInstalledDriver(DriverRefNum refNum, SInt8 ioPermission)
  115.     // See comment in header file.
  116. {
  117.     OSErr                 err;
  118.     Str255                driverName;
  119.     DriverRefNum    realRefNum;
  120.  
  121.     // Check parameters.
  122.     err = noErr;
  123.     if (ioPermission != fsRdWrPerm) {
  124.         err = paramErr;
  125.     }
  126.     
  127.     // Get the name of the driver, then simply open it.
  128.     if (err == noErr) {
  129.         err = TradGetDriverInformation(refNum, nil, nil, driverName, nil);
  130.     }
  131.     if (err == noErr) {
  132.         if ( driverName[0] == 0 ) {
  133.             err = paramErr;
  134.         }
  135.     }
  136.     if (err == noErr) {
  137.         err = OpenDriver(driverName, &realRefNum);
  138.     }
  139.     if (err == noErr) {
  140.         if (realRefNum != refNum) {
  141.             err = paramErr;        // My favourite error code -- at some intrinsic level, every error is a paramErr (-;
  142.         }
  143.     }
  144.     
  145.     return (err);
  146. }
  147.  
  148. ///////////////////////////////////////////////////////////////////////////
  149.  
  150. extern pascal OSErr TradLookupDrivers(UnitNumber beginningUnit,
  151.                                         UnitNumber endingUnit,
  152.                                         Boolean emptyUnits,
  153.                                         ItemCount *returnedRefNums, 
  154.                                         DriverRefNum *refNums)
  155.     // See comment in header file.
  156. {
  157.     OSErr err;
  158.     AuxDCEHandle     *unitTable;
  159.     ItemCount         maxRefNums;
  160.     UnitNumber         currentUnit;
  161.     
  162.     // Sanity check the parameters.
  163.     if ( endingUnit > TradHighestUnitNumber() ) {
  164.         endingUnit = TradHighestUnitNumber();
  165.     }
  166.     err = noErr;
  167.     if ( beginningUnit > TradHighestUnitNumber() ) {
  168.         err = badUnitErr;
  169.     }
  170.     if (err == noErr) {
  171.         if (beginningUnit > endingUnit ) {
  172.             err = paramErr;
  173.         }
  174.     }
  175.  
  176.     // Now do the real work...
  177.     if (err == noErr) {
  178.         unitTable = (AuxDCEHandle *) LMGetUTableBase();
  179.  
  180.         maxRefNums = *returnedRefNums;
  181.         
  182.         // Loop through each unit table entry from beginningUnit to endingUnit inclusive.
  183.         *returnedRefNums = 0;
  184.         currentUnit = beginningUnit;
  185.         while ( currentUnit <= endingUnit ) {
  186.  
  187.             // If we've still got space to return a unit...
  188.             if ( *returnedRefNums < maxRefNums ) {
  189.             
  190.                 // and we're interested in this unit...
  191.                 if (    (emptyUnits && unitTable[currentUnit] == nil) ||
  192.                             (!emptyUnits && unitTable[currentUnit] != nil) ) {
  193.                     
  194.                     // then copy the unit out to the caller's array
  195.                     refNums[*returnedRefNums] = ~currentUnit;
  196.                     *returnedRefNums += 1;
  197.                 }
  198.             }
  199.             currentUnit += 1;
  200.         }
  201.     
  202.     }
  203.     
  204.     return (err);
  205. }
  206.  
  207. ///////////////////////////////////////////////////////////////////////////
  208.  
  209. enum {
  210.     kNoUnitNumber = 0xFFFF
  211. };
  212.  
  213. static UnitNumber IsDriverInstalled(ConstStr255Param name, UnitNumber skipThisUnit)
  214.     // Look through the unit table to see if there is a driver with this name
  215.     //  already installed.  Note that you might consider calling OpenDriver
  216.     //  here, but that would be wrong.  OpenDriver has similar semantics, but
  217.     //  if it fails to find a driver in the unit table it will search the
  218.     //  current resource chain looking for a DRVR resource to install.
  219.     //  Given that it's likely our client has a DRVR resource in their
  220.     //  resource chain ('cause they're messing around trying to install
  221.     //  drivers), and that OpenDriver will install it without detaching
  222.     //  it from the client's resource file, and that the client's
  223.     //  resource file may go away (ie they're a DropMounter-like application
  224.     //  or some INIT running at system startup), this would be bad.
  225. {
  226.     UnitNumber    endingUnit;
  227.     UnitNumber    unit;
  228.     Str255            unitName;
  229.     
  230.     endingUnit = TradHighestUnitNumber();
  231.     
  232.     for (unit = 0; unit <= endingUnit; unit++) {
  233.         if ( TradGetDriverInformation(~unit, nil, nil, unitName, nil) == noErr) {
  234.             if ( unit != skipThisUnit && EqualString(name, unitName, false, true) ) {
  235.                 return (unit);
  236.             }
  237.         }
  238.     }
  239.     
  240.     return (kNoUnitNumber);
  241. }
  242.  
  243. ///////////////////////////////////////////////////////////////////////////
  244.  
  245. enum {
  246.     kMaximumNumberOfUnitTableEntries = 1024,
  247.     // kMaximumNumberOfUnitTableEntries = 8000,
  248.     
  249.     // kMaximumNumberOfUnitTableEntries is documented in Technote
  250.     //  DV 23 "Driver Education" <http://devworld.apple.com/dev/technotes/dv/dv_23.html>
  251.     //  as being the maximum size that the classic Device Manager
  252.     //  would grow the unit table.  In theory, this limits the system
  253.     //  to 128 unit table entries.
  254.     // However the traditional Mac OS is capable of dealing with much more
  255.     //  than 128 units.  In fact, some multi-port serial card vendors
  256.     //  regularly install more.
  257.     // Prior to Mac OS 8, the PCI DriverLoaderLib enforced the 128 limit.
  258.     //  I filed a bug against the PCI DriverLoaderLib to get this limit
  259.     //  raised, and the new limit under Mac OS 8 is 1024.
  260.     // Given that official sanction, I have now raised the standard
  261.     //  limit enforced by this library to 1024.  I supply an alternative
  262.     //  maximum (8000), designed to keep the unit table smaller than 32K.
  263.     //  This is important because many people use 68K word indexing
  264.     //  (ie x(a0,d0.w) to to access the entries.
  265.     // I have tested TradDriverLoaderLib installing up to 500 device
  266.     //  drivers.  
  267.     
  268.     kNumberOfEntriesToGrowUnitTable = 4
  269.     
  270.     // Technote DV 23 "Driver Education"
  271.     //  <http://devworld.apple.com/dev/technotes/dv/dv_23.html>
  272.     //  documents that the system grows the unit table by 4 entries
  273.     //  at a time.
  274. };
  275.  
  276. ///////////////////////////////////////////////////////////////////////////
  277.  
  278. static OSErr GrowUnitTable()
  279.     // This routine grows the unit table by kNumberOfEntriesToGrowUnitTable,
  280.     //  up to a maximum of kMaximumNumberOfUnitTableEntries.  The routine
  281.     //  is guaranteed to grow the table by at least one entry, or fail
  282.     //  with an error.
  283. {
  284.     OSErr        err;
  285.     Ptr         oldTable;
  286.     Ptr         newTable;
  287.     UInt32    oldCount;
  288.     UInt32    newCount;
  289.  
  290.     // Get the info about the old table, and calculate the new table size.    
  291.     oldTable = LMGetUTableBase();
  292.     oldCount = LMGetUnitTableEntryCount();
  293.     newCount = oldCount + kNumberOfEntriesToGrowUnitTable;
  294.  
  295.     // Guard against growing the table too big.    
  296.     err = noErr;
  297.     if (newCount > kMaximumNumberOfUnitTableEntries) {
  298.         err = unitTblFullErr;
  299.     }
  300.     
  301.     // Allocate the new unit table in the system heap.  Note that we
  302.     //  clear the newly allocated memory, so that later on, when we
  303.     //  use this memory as the new unit table, the newly allocated
  304.     //  entries will be empty.
  305.  
  306.     if (err == noErr) {
  307.         newTable = NewPtrSysClear( newCount * sizeof(AuxDCEHandle));
  308.         err = MemError();
  309.     }
  310.  
  311.     // Copy the unit table entries over to the new table and then switch
  312.     //  to that table.  Note that this sequence doesn't disable interrupts,
  313.     //  instead it relies on the fact that programs can't modify the
  314.     //  unit table at interrupt time, and thus we, running at non-interrupt
  315.     //  time, have exclusive write access to the table.
  316.  
  317.     // Note that the sequence of these next few lines is *very* important.
  318.     //  If we did this in any other order, you could get to a situation
  319.     //  where interrupt code might be looking at an inconsistent 
  320.     //  unit table, which would be bad.
  321.     
  322.     // The sequence is:
  323.     //  1. copy the old unit table entries to the new table
  324.     //  2. change the unit table base pointer, so that interrupts
  325.     //         start using the new unit table
  326.     //  3. then change the unit table count, so that we have
  327.     //         more entries available
  328.     
  329.     if (err == noErr) {
  330.         BlockMoveData(oldTable, newTable, oldCount * sizeof(AuxDCEHandle));    // 1.
  331.         LMSetUTableBase(newTable);                                                                                    // 2.
  332.         LMSetUnitTableEntryCount(newCount);                                                                    // 3.
  333.         
  334.         // Now its safe to dispose of the old unit table.
  335.         DisposePtr(oldTable);
  336.     }
  337.  
  338.     return (err);    
  339. }
  340.  
  341. ///////////////////////////////////////////////////////////////////////////
  342.  
  343. static OSErr FindFreeUnitNumber(UnitNumber beginningUnit,
  344.                                 UnitNumber endingUnit, 
  345.                                 UnitNumber *foundUnit)
  346.     // This routine walks the unit table looking for a free
  347.     //  slot.  The slot must be between beginningUnit
  348.     //  and endingUnit.  If endingUnit is greater than
  349.     //  TradHighestUnitNumber(), then we're allowed
  350.     //  to grow the unit table to meet our needs.
  351. {
  352.     OSErr err;
  353.     Boolean found;
  354.     UnitNumber currentUnit;
  355.     UnitNumber trueEndingUnit;
  356.     AuxDCEHandle *unitTable;
  357.     
  358.     unitTable = (AuxDCEHandle *) LMGetUTableBase();
  359.     
  360.     // Find trueEndingUnit, which is the minimum
  361.     //  of endingUnit and the highest unit number.
  362.     trueEndingUnit = endingUnit;
  363.     if ( trueEndingUnit > TradHighestUnitNumber() ) {
  364.         trueEndingUnit = TradHighestUnitNumber();
  365.     }
  366.  
  367.     // Scan through the unit table, starting at beginningUnit
  368.     //  and ending at trueEndingUnit, looking for an
  369.     //  empty slot.
  370.     currentUnit = beginningUnit;
  371.     found = false;
  372.     while (currentUnit <= trueEndingUnit && !found) {
  373.         found = (unitTable[currentUnit] == nil);
  374.         if (!found) {
  375.             currentUnit += 1;
  376.         }
  377.     }
  378.  
  379.     // Finish up.    
  380.     if (found) {
  381.         // We found an empty slot, return it.
  382.         *foundUnit = currentUnit;
  383.         err = noErr;
  384.     } else {
  385.  
  386.         // We didn't find an empty slot.  If we're
  387.         //  allowed to, grow the unit table, otherwise
  388.         //  just return an error.
  389.         
  390.         if (endingUnit > trueEndingUnit) {
  391.             err = GrowUnitTable();
  392.             if (err == noErr) {
  393.                 *foundUnit = trueEndingUnit + 1;
  394.             }
  395.         } else {
  396.             err = unitTblFullErr;
  397.         }
  398.     }
  399.     
  400.     return (err);    
  401. }
  402.  
  403. ///////////////////////////////////////////////////////////////////////////
  404.  
  405. extern pascal OSErr TradInstallDriverFromPtr(DRVRHeaderPtr driver,
  406.                                                 UnitNumber beginningUnit,
  407.                                                 UnitNumber endingUnit,
  408.                                                 DriverRefNum *refNum)
  409.     // See comment in header file.
  410. {
  411.     OSErr err;
  412.     UnitNumber foundUnit;
  413.     AuxDCEHandle theDCE;
  414.     
  415.     // Sanity check parameters.
  416.     err = noErr;
  417.     if ( driver == nil ) {
  418.         err = paramErr;
  419.     }
  420.     if ( beginningUnit > TradHighestUnitNumber() ) {
  421.         err = badUnitErr;
  422.     }
  423.     if ( err == noErr && beginningUnit > endingUnit ) {
  424.         err = paramErr;
  425.     }
  426.     
  427.     // Check whether this driver is already installed.
  428.     if ( err == noErr ) {
  429.         // Check whether it's already installed.
  430.         foundUnit = IsDriverInstalled(&driver->drvrName[0], kNoUnitNumber);
  431.         if (foundUnit != kNoUnitNumber) {
  432.             // Return the refnum of the existing driver to the caller.
  433.             *refNum = ~foundUnit;
  434.             err = dupFNErr;
  435.         }
  436.     }
  437.     
  438.     // Now walk the unit table looking for a free slot.
  439.     if (err == noErr) {
  440.         err = FindFreeUnitNumber(beginningUnit, endingUnit, &foundUnit);
  441.     }
  442.  
  443.     // We've got a free slot, so let's install the device driver.
  444.     //  Note that we use DriverInstallReserveMem, rather than the standard
  445.     //  DriverInstall, so that the DCE is allocated low in the system
  446.     //  heap.  DriverInstallReserveMem was introduced with the 128K ROM.
  447.  
  448.     if (err == noErr) {
  449.         err = DriverInstallReserveMem(driver, ~foundUnit);
  450.     }
  451.     
  452.     // Now do some important tidying up.
  453.     if (err == noErr) {
  454.  
  455.         // Return the refNum to the caller.
  456.         *refNum = ~foundUnit;
  457.  
  458.         theDCE = (AuxDCEHandle) GetDCtlEntry(*refNum);
  459.         
  460.         // Now setup the DCE properly.  There's a whole pile of things we
  461.         //  have to do, mainly because DriverInstall is such a brain-dead
  462.         //  routine.
  463.         
  464.         // First up, DriverInstall seems to ignore the first parameter
  465.         //  passed to it, so we have to blat the pointer to the driver code in
  466.         //  yourself afterwards.
  467.         
  468.         (**theDCE).dCtlDriver = (Ptr) driver;
  469.  
  470.         // Then we have to set up the flags.  We do this by copying the flags
  471.         //  out of the first word of the driver code.  We make sure to clear
  472.         //  the dRAMBased bit because we're actually a pointer-based driver
  473.         //  and DriverInstallReserveMem sets it to provisionally indicate that
  474.         //  we're a handle based driver.  We also set dNeedLock because
  475.         //  we want the the Device Manager to lock down the DCE.
  476.         
  477.         (**theDCE).dCtlFlags = (driver->drvrFlags & ~dRAMBasedMask) | dNeedLockMask;
  478.  
  479.         // There's also a bunch of fields we copy straight across without
  480.         //  any modification.  You might expect DriverInstall to copy
  481.         //  across these fields from the driver header to the DCE, but it doesn't
  482.         //  do that, so we do it ourselves.
  483.  
  484.         (**theDCE).dCtlDelay = driver->drvrDelay;
  485.         (**theDCE).dCtlEMask = driver->drvrEMask;
  486.         (**theDCE).dCtlMenu  = driver->drvrMenu;
  487.  
  488.         // Finally, we lock the DCE.
  489.         // Note that strictly speaking we don't need to HLock the DCE
  490.         //  because the Device Manager will do it when it you open a driver
  491.         //  that has dNeedLock set.  However, we want to
  492.         //  lock it now because DriverInstallReserveMem has just made sure
  493.         //  that the DCE was created low in the system heap, so we might as
  494.         //  well lock it down low rather than let it float.
  495.  
  496.         HLock( (Handle) theDCE );
  497.     }
  498.     
  499.     return (err);
  500. }
  501.  
  502. ///////////////////////////////////////////////////////////////////////////
  503.  
  504. extern pascal OSErr TradInstallDriverFromHandle(DRVRHeaderHandle driver,
  505.                                                 UnitNumber beginningUnit,
  506.                                                 UnitNumber endingUnit,
  507.                                                 DriverRefNum *refNum)
  508.     // See comment in header file.
  509. {
  510.     OSErr err;
  511.     Size  driverSize;
  512.     DRVRHeaderPtr driverPtr;
  513.     
  514.     driverPtr = nil;
  515.     
  516.     err = noErr;
  517.     if (driver == nil || *driver == nil) {
  518.         err = paramErr;
  519.     }
  520.     if (err == noErr) {
  521.         driverSize = GetHandleSize( (Handle) driver );
  522.     }
  523.     if (err == noErr) {
  524.         driverPtr = (DRVRHeaderPtr) NewPtrSys( driverSize );
  525.         err = MemError();
  526.     }
  527.     
  528.     if (err == noErr) {
  529.         // This is *not* a BlockMoveData call. This time, we really are moving code!
  530.         //  I could have put cache flushing code in here, but then I would have
  531.         //  had to check whether it was available or not.
  532.         BlockMove( *driver, driverPtr, driverSize );
  533.         
  534.         err = TradInstallDriverFromPtr(driverPtr, beginningUnit, endingUnit, refNum);
  535.     }
  536.     
  537.     // Clean up.
  538.     if (err != noErr) {
  539.         // We're returning an error.  The API says we should leave the handle untouched,
  540.         //  but we should definitely clean up our new copy of the driver code.
  541.         if (driverPtr != nil) {
  542.             DisposePtr( (Ptr) driverPtr );
  543.         }
  544.     }
  545.     
  546.     return (err);
  547. }
  548.  
  549. ///////////////////////////////////////////////////////////////////////////
  550.  
  551. extern pascal OSErr TradInstallDriverFromResource(SInt16 rsrcID, StringPtr rsrcName,
  552.                                                 UnitNumber beginningUnit,
  553.                                                 UnitNumber endingUnit,
  554.                                                 DriverRefNum *refNum)
  555.     // See comment in header file.
  556. {
  557.     OSStatus err;
  558.     Handle driverHandle;
  559.     
  560.     // Note: We don't care which zone the resource gets loaded, because 
  561.     //  TradInstallDriverFromHandle makes a copy of it anyway.
  562.  
  563.     // Get the resource, using either rsrcID or rsrcName.
  564.     if (rsrcName == nil) {
  565.         driverHandle = Get1Resource('DRVR', rsrcID);
  566.     } else {
  567.         driverHandle = Get1NamedResource('DRVR', rsrcName);
  568.     }
  569.     
  570.     // Set err if we couldn't get the resource.
  571.     if (driverHandle == nil) {
  572.         err = ResError();
  573.         if (err == noErr) {
  574.             err = resNotFound;
  575.         }
  576.     } else {
  577.         // Make sure we're not killed by some clown making the 'DRVR' purgeable.
  578.         HNoPurge(driverHandle);                    
  579.         err = MemError();
  580.     }
  581.     
  582.     // Now install the driver as if we'd got it from a memory handle.    
  583.     if (err == noErr) {
  584.         err = TradInstallDriverFromHandle( (DRVRHeaderHandle) driverHandle, beginningUnit, endingUnit, refNum);
  585.  
  586.         ReleaseResource(driverHandle);
  587.         if (err == noErr) {
  588.             err = ResError();
  589.         }
  590.     }
  591.     
  592.     return (err);
  593. }
  594.  
  595. ///////////////////////////////////////////////////////////////////////////
  596.  
  597. extern pascal OSErr TradGetDriverInformation(DriverRefNum refNum,
  598.                                                 UnitNumber *thisUnit,
  599.                                                 DriverFlags *flags,
  600.                                                 StringPtr name,
  601.                                                 DRVRHeaderPtr *driverHeader
  602.                                                 )
  603.     // See comment in header file.
  604. {
  605.     OSErr err;
  606.     UnitNumber             tmpUnit;
  607.     AuxDCEHandle        tmpDCE;
  608.     DRVRHeaderPtr        tmpHeader;
  609.     DRVRHeaderHandle    tmpDriverHandle;
  610.     
  611.     // Get some initial information.
  612.     tmpUnit = ~refNum;
  613.     
  614.     // Sanity check the refNum parameter.
  615.     err = noErr;
  616.     if (tmpUnit > TradHighestUnitNumber()) {
  617.         err = badUnitErr;
  618.     }
  619.     if (err == noErr) {
  620.         tmpDCE = (AuxDCEHandle) GetDCtlEntry(refNum);
  621.         if ( tmpDCE == nil ) {
  622.             err = unitEmptyErr;
  623.         }
  624.     }
  625.     if (err == noErr) {
  626.         if ( (*tmpDCE == nil) || (GetHandleSize( (Handle) tmpDCE) < sizeof(DCtlEntry)) ) {
  627.             err = dceExtErr;
  628.         }
  629.     }
  630.     
  631.     // Get the information from the DCE.
  632.     if (err == noErr) {
  633.  
  634.         // From the DCE, find the DRVR header.  This can fail for a number of reasons:
  635.         //     1. dCtlDriver is nil
  636.         //     2. the driver is handle based, and the handle's master point is nil
  637.         //     3. the driver is handle based, and the driver's handle is too small
  638.         // In all of these cases, we set tmpHeader to nil, returning nil to our
  639.         // client.
  640.         
  641.         tmpHeader = (DRVRHeaderPtr) (**tmpDCE).dCtlDriver;
  642.         if ( tmpHeader != nil ) {
  643.             if ( ((**tmpDCE).dCtlFlags & dRAMBasedMask) != 0 ) {
  644.  
  645.                 tmpDriverHandle = (DRVRHeaderHandle) tmpHeader;
  646.                 
  647.                 if ( (*tmpDriverHandle != nil) &&
  648.                             (GetHandleSize( (Handle) tmpDriverHandle) >= sizeof(DRVRHeader)) ) {
  649.                     tmpHeader = *tmpDriverHandle;
  650.                 }
  651.             }
  652.         }
  653.         
  654.         // Now copy out the various requested parameters
  655.         if (thisUnit != nil) {
  656.             *thisUnit = tmpUnit;
  657.         }
  658.         if (flags != nil) {
  659.             *flags = (**tmpDCE).dCtlFlags;
  660.         }
  661.         if (name != nil) {
  662.             if ( tmpHeader == nil ) {
  663.                 name[0] = 0;
  664.             } else {
  665.                 BlockMoveData(&tmpHeader->drvrName[0], name, tmpHeader->drvrName[0] + 1);
  666.             }
  667.         }
  668.         if (driverHeader != nil) {
  669.             *driverHeader = tmpHeader;
  670.         }
  671.     }
  672.     
  673.     return (err);
  674. }
  675.  
  676. ///////////////////////////////////////////////////////////////////////////
  677.  
  678. extern pascal OSErr TradRemoveDriver(DriverRefNum refNum, Boolean immediate)
  679.     // See comment in header file.
  680. {
  681.     OSErr                 err;
  682.     DriverFlags     flags;
  683.     DRVRHeaderPtr driverHeader;
  684.  
  685.     // Check parameters.
  686.     err = noErr;
  687.     if (immediate) {
  688.         err = paramErr;
  689.     }
  690.  
  691.     // Get information about the driver we're closing.
  692.     if (err == noErr) {
  693.         err = TradGetDriverInformation(refNum, nil, &flags, nil, &driverHeader);
  694.     }
  695.     if (err == noErr) {
  696.         if ( driverHeader == nil ) {
  697.             err = paramErr;
  698.         }
  699.     }
  700.     
  701.     // If the driver is open, close it.
  702.     if (err == noErr) {
  703.         if ( (flags & dOpenedMask) != 0 ) {
  704.             err = CloseDriver(refNum);
  705.         }
  706.     }
  707.     
  708.     // Now call the system to remove the driver from the unit table.  Note that this
  709.     //  works because of a subtlety in DriverRemove.  If the driver being removed
  710.     //  is a RAM-based driver (which our drivers aren't), DriverRemove will call
  711.     //  ReleaseResource on the dCtlDriver.  We don't want this, so we make our drivers
  712.     //  not RAM-based.
  713.     
  714.     if (err == noErr) {
  715.         err = DriverRemove(refNum);
  716.     }
  717.     
  718.     if (err == noErr) {
  719.         // All is cool, so let's dispose of the code.
  720.         DisposePtr( (Ptr) driverHeader);
  721.     }
  722.     
  723.     return (err);
  724. }
  725.  
  726. ///////////////////////////////////////////////////////////////////////////
  727.  
  728. extern pascal OSErr TradRenameDriver(DriverRefNum refNum, ConstStr255Param newDriverName)
  729.     // See *important* comment in header file.
  730. {
  731.     OSErr             err;
  732.     Str255             driverName;
  733.     DRVRHeaderPtr     driverHeader;
  734.     
  735.     err = noErr;
  736.     if ( newDriverName[0] == 0 ) {
  737.         err = paramErr;
  738.     }
  739.     if (err == noErr) {
  740.         // Get information about the driver we're renaming.
  741.         err = TradGetDriverInformation(refNum, nil, nil, driverName, &driverHeader);
  742.     }
  743.     if (err == noErr) {
  744.         if ( driverHeader == nil ) {
  745.             err = paramErr;
  746.         }
  747.     }
  748.     
  749.     // Now check the name lengths.  See comment in implementation for details.
  750.     if (err == noErr) {
  751.         if ( newDriverName[0] > driverName[0] ) {
  752.             err = paramErr;
  753.         }
  754.     }
  755.     
  756.     // Now check whether the new name is already present in the unit table.
  757.     if (err == noErr) {
  758.         if ( IsDriverInstalled(newDriverName, ~refNum) != kNoUnitNumber ) {
  759.             err = dupFNErr;
  760.         }
  761.     }
  762.     
  763.     // Now copy in the new driver name.
  764.     if (err == noErr) {
  765.         BlockMoveData( newDriverName, &driverHeader->drvrName[0], newDriverName[0] + 1 );
  766.     }
  767.     
  768.     return (err);
  769. }
  770.